package tau.dimes.data;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
import java.util.Vector;

public class Table
{
	private int numOfColumns = 0;
	private int numOfRows = 0;
	
	/**
	 * Dynamic table built from Vectors
	 */
	private Vector<Row> dataTable = new Vector<Row>();
	
	/**
	 * Dynamic collection of the table columns
	 */
	private Vector<Column> columns = new Vector<Column>();

	/**
	 * 
	 * @param numOfColumns
	 * @param numOfRows
	 */
	public Table(int numOfColumns, int numOfRows)
	{
		this.numOfColumns = numOfColumns;
		this.numOfRows = numOfRows;		
	}
	
	/**
	 * Creates a Table from ResultSet object 
	 * @param rs - the ResultSet source
	 * @throws SQLException
	 * @throws TableException 
	 */
	public Table(ResultSet rs) throws SQLException, TableException
	{
		ResultSetMetaData rsmd = rs.getMetaData();
		
		// Check if this is the first result set in this table
		if (numOfColumns == 0) 
			numOfColumns = rsmd.getColumnCount();
		else
			if (numOfColumns != rsmd.getColumnCount())
			{
				throw new TableException("Invalid column number");
			}
				
		// Copy data from ResultSet object into the Table
		copyResultSetToTable(rs);
		
		// Update the columns collection with the columns names and types
		for (int i = 1; i <= numOfColumns; i++)
		{
			Column column = new Column();
			column.setColumnName(rsmd.getColumnName(i));
			column.setColumnType(rsmd.getColumnType(i));
			
			columns.add(column);
		}
	}

	/**
	 * @param rs
	 * @throws SQLException
	 */
	public void copyResultSetToTable(ResultSet rs) throws SQLException
	{
		rs.beforeFirst(); // This can be removed only if we can ensure the ResultSet is initialized
		while (rs.next())
		{
			// Create new row and insert the data from the ResultSet 
			Row row = new Row();
			
			for (int i = 1; i <= numOfColumns; i++)
				row.add(rs.getString(i));
			
			dataTable.add(row);
			numOfRows++;			
		}
	}
		
	/**
	 * @return the numOfColumns
	 */
	public int getNumOfColumns()
	{
		return numOfColumns;
	}

	/**
	 * @return the numOfRows
	 */
	public int getNumOfRows()
	{
		return numOfRows;
	}

	/**
	 * Adds a row at the end of the table
	 * @param row - the row to add
	 * @return the index of the added row
	 * @throws TableException 
	 */
	public int addRow(Row row) throws TableException
	{
		if (row.size() != numOfColumns)
		{
			throw new TableException("Invalid column number");
		}
		
		dataTable.add(row);
		
		return numOfRows++;
	}
	
	/**
	 * Adds a column to the table
	 * @param column - the column to add
	 * @return the index of the added column
	 */
	public int addColumn(Column column)
	{		
		columns.add(column);
		
		return numOfColumns++;
	}
	
	/**
	 * 
	 * @param column
	 * @param columnData
	 * @return
	 * @throws TableException 
	 */
	public int addColumn(Column column, Vector<String> columnData) throws TableException
	{
		if (columnData.size() != numOfRows)
			throw new TableException("Invalid row number");
						
		for (int i = 0; i < numOfRows; i++)
			dataTable.get(i).add(columnData.get(i));
				
		return addColumn(column);
	}
	
	/**
	 * 
	 * @param index
	 * @return
	 * @throws TableException 
	 */
	public String getColumnNameByIndex(int index) throws TableException
	{
		if (index < 0 || index >= numOfColumns)
			throw new TableException("Invalid column index");
				
		return columns.get(index).getColumnName();
	}
	
	/**
	 * 
	 * @param index
	 * @return
	 * @throws TableException 
	 */
	public int getColumnTypeByIndex(int index) throws TableException
	{
		if (index < 0 || index >= numOfColumns)
			throw new TableException("Invalid column index");
				
		return columns.get(index).getColumnType();
	}
	
	/**
	 * Gets a column's index by name
	 * @param columnName - the column name
	 * @return the column index if found, -1 if not
	 */
	public int getColumnIndexByName(String columnName)
	{
		for (int i = 0; i < columns.size(); i++)
		{
			Column column = columns.get(i);
			if (column.getColumnName().equals(columnName))
				return i;
		}
		
		return -1;
	}
	
	public Vector<String> getColumnData(int columnIndex) throws TableException
	{
		if ((columnIndex < 0) || (numOfColumns <= columnIndex)) 
			throw new TableException("Invalid column index");
				
		Vector<String> column = new Vector<String>();
		
		for (Row row : dataTable) {
			column.add(row.get(columnIndex));
		}
		
		return column;
	}
	
	public Row getRow(int index)
	{
		return this.dataTable.get(index);
	}

	public List<Row> rows()
	{
		return dataTable;
	}
	
	public List<Column> columns()
	{
		return columns;
	}
}
